#include "cola.h"
#include <stdio.h>
#define PI 3.14159265358979323846
#define E 2.71828182845904523536

void* malloc(size_t size);

void free(void* ptr);

void print_test(char* name, bool result){

	printf("%s: %s\n", name, result? "OK" : "ERROR");
}

//Realiza un encole masivo de un puntero pasado por parametro.
//Devuelve true si se pudo realizar el encole y false en su defecto.
bool encolar_masivo(cola_t* cola, void* ptr){

	int i;

	for(i=0;i<100000;i++){

		if (!cola_encolar(cola,ptr)) return false;
	}

	return true;
}

//Simula la llega de aviones a un aeropuerto. Devuelve true si se desencola
//primero el primero que llego y asi sucesivamente y false si esto no ocurre.
bool simulacion_aeronautica(void){

	char* aviones[]={"American Airlines","United","TAM","Aerolineas Argentinas"};

	cola_t* torre_control=cola_crear();

	int i;
	
	for(i=0;i<4;i++){
		//Encolo cada uno de los aviones en orden.
		cola_encolar(torre_control,aviones[i]);
	}

	for(i=0;i<4;i++){
		//Si el orden de salida no es el mismo que el de llegada, devuelvo false
		if( (cola_desencolar(torre_control)) != aviones[i] ){

			cola_destruir(torre_control,NULL);

			return false;
		}
	}

	cola_destruir(torre_control,NULL);

	return true;
}

//Encola el mismo elemento que esta desencolando. Como se encolan solo dos
//elementos, si se hace esto un numero par de veces, el primero al final
//de la prueba sera el primero que encole. Si esto ocurre devuelve true, sino
//devuelve false.
bool loop_de_encole(void){
	
	int i;
	
	bool result;
	
	cola_t* cola_loop=cola_crear();
	
	double arreglo[]={PI,E};
	
	cola_encolar(cola_loop, &arreglo[0]);
	
	cola_encolar(cola_loop, &arreglo[1]);
	
	for(i=0;i<100;i++){
		//Encola el mismo elemento que desencola un numero par de veces.
		cola_encolar(cola_loop,cola_desencolar(cola_loop));
	}
	//Me fijo que el primero de la cola sea el primero de mi lista y guardo
	//el resultado del chequeo en una variable para poder destruir mi cola.	
	result=cola_ver_primero(cola_loop)==&arreglo[0];

	cola_destruir(cola_loop,NULL);
	
	return result;
}

//Realiza un encole masivo de elementos en memoria dinamica y devuelve true
//si pudo encolarlos a todos y false si esto no ocurrio.
bool prueba_free_destruir(void){
	
	int i;
	
	int* k;

	cola_t* colafree=cola_crear();
	
	for(i=0;i<100000;i++){
		
		k=(int*)malloc(sizeof(int));
		
		if(cola_encolar(colafree,k)==false) return false;
		
	}
	
	cola_destruir(colafree,free);
	
	return true;
	
}

//Agrupa todas las pruebas unitarias en una sola funcion e imprime su resultado.
void pruebas_unitarias(void){

	char *pal1="pal1";

	char *pal2="pal2";

	char *pal3="pal3";

	cola_t* cola=cola_crear();
	
	//Manejo de errores.
	printf("\n\n~~~~~~~~~~Manejo de errores del TAD Cola~~~~~~~~~~\n\n");
	
	print_test("Cola se crea",cola!=NULL);
	
	print_test("Cola inexistente no encola",cola_encolar(NULL,pal1)==false);
	
	print_test("Cola no encola puntero nulo",cola_encolar(cola,NULL)==false);
	
	print_test("Desencolar cola vacia",cola_desencolar(cola)==NULL);
	
	print_test("Error al desencolar cola inexistente",cola_desencolar(NULL)==NULL);
	
	print_test("Ve el primero de cola vacia",cola_ver_primero(cola)==NULL);
	
	print_test("Error al ver primero de cola inexistente",cola_ver_primero(NULL)==NULL);
	
	//Pruebas del uso de la cola.
	printf("\n\n~~~~~~~~~~Pruebas del uso del TAD cola~~~~~~~~~~\n\n");
	
	print_test("Cola esta vacia",cola_esta_vacia(cola));

	print_test("Cola encola elemento",cola_encolar(cola,pal1));

	print_test("Cola encola elemento",cola_encolar(cola,pal2));

	print_test("Cola no esta vacia",!cola_esta_vacia(cola));

	print_test("Cola desencola elemento",cola_desencolar(cola)==pal1);

	print_test("Cola ver primero",cola_ver_primero(cola)==pal2);

	print_test("Cola desencola elemento",cola_desencolar(cola)==pal2);

	print_test("Cola se vacia",cola_esta_vacia(cola));

	print_test("Encolar muchos elementos",encolar_masivo(cola,pal3));

	cola_destruir(cola,NULL);

	print_test("Simulacion Aeronautica",simulacion_aeronautica());
	
	print_test("Loop de encole",loop_de_encole());
	
	print_test("Encolar muchos elementos de memoria dinamica",prueba_free_destruir());
	
	printf("Fin de las pruebas.\n");
}

int main(void){
	pruebas_unitarias();
	return 0;
}
